package il.ac.tau.cvws.scrabblesidekick.server.engine.recoginition.calibration.colorbasedcalibration;

import il.ac.tau.cvws.scrabblesidekick.server.util.cv.CvUtil;
import il.ac.tau.cvws.scrabblesidekick.shared.util.math.Point;

import java.util.HashSet;
import java.util.Set;

import com.googlecode.javacv.cpp.opencv_core;
import com.googlecode.javacv.cpp.opencv_core.CvArr;
import com.googlecode.javacv.cpp.opencv_core.CvPoint2D32f;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import com.googlecode.javacv.cpp.opencv_imgproc;

/* Utility functions for the color-based calibration algorithm.
 */
public class ColorBaseCalibrationUtil
{
	/* Remove some of the image artifacts by repeated dilation and erosion.
	 */
	public static IplImage removeArtifacts(IplImage srcImage)
	{
		IplImage dilImg   = CvUtil.dilateImage(srcImage, 15);
		IplImage eroImg   = CvUtil.erodeImage(dilImg, 31);
		IplImage superImg = CvUtil.dilateImage(eroImg, 31);
		
		return superImg;
	}
	
	/* Filters the given image by the given hue (thresholds). The resulting image
	 * will have white pixels where the original pixel did not match the hue, and
	 * black otherwise.
	 */
	public static IplImage getHueThreshold(IplImage srcImg, double hueLower, double hueUpper) 
	{
		IplImage dilImg = CvUtil.dilateImage(srcImg, 3);
		IplImage conImage = CvUtil.contrastImage(dilImg, 0.5, 5);
		
        IplImage imgHSV = IplImage.create(conImage.width(), conImage.height(), conImage.depth(), 3);
        opencv_imgproc.cvCvtColor(conImage, imgHSV, opencv_imgproc.CV_BGR2HSV);
        
        IplImage imgThreshold = IplImage.create(srcImg.width(), srcImg.height(), srcImg.depth(), 1);
        opencv_core.cvInRangeS(imgHSV,
        		opencv_core.cvScalar(hueLower, 120, 120, 0),
        		opencv_core.cvScalar(hueUpper, 255, 255, 0), imgThreshold);
        
        imgHSV.release();
        
        opencv_imgproc.cvSmooth(imgThreshold, imgThreshold, opencv_imgproc.CV_MEDIAN, 13);

        return imgThreshold;
    }
	
	/* Detect the edges of the colored squares by using feature detection.
	 */
	public static Set<Point> findEdges(IplImage imgSrc)
	{
		int winSize = 3;
		
		IplImage eigImage = IplImage.create(imgSrc.width(), imgSrc.height(), opencv_core.IPL_DEPTH_32F, 1);
		IplImage tmpImage = IplImage.create(imgSrc.width(), imgSrc.height(), opencv_core.IPL_DEPTH_32F, 1);
		
		int maxCorners    = 1000; 
		int[] cornerCount = {maxCorners};
		CvPoint2D32f corners = new CvPoint2D32f(maxCorners);
		
		CvArr mask = null;
		
		opencv_imgproc.cvGoodFeaturesToTrack(imgSrc, eigImage, tmpImage, corners, cornerCount, 0.05, 5.0, mask, 3, 0, 1);
		opencv_imgproc.cvFindCornerSubPix(imgSrc, corners, cornerCount[0], opencv_core.cvSize(winSize, winSize), opencv_core.cvSize(-1, -1),
										  opencv_core.cvTermCriteria(opencv_core.CV_TERMCRIT_ITER | opencv_core.CV_TERMCRIT_EPS, 20, 0.03));

		int limitsCount = cornerCount[0];
		
		Set<Point> pointsSet = new HashSet<Point>();
		
		for(int i = 0; i < limitsCount; i++)
		{
			pointsSet.add(new Point(corners.position(i).x(), corners.position(i).y(), 0.0));
		}
		
		return pointsSet;
	}
}
